﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Windows.Forms;
using System.Diagnostics;
using System.Net.NetworkInformation;
using MatthiWare.PortChecker.Events;

namespace MatthiWare.PortChecker
{
    public class CheckPortTask
    {
        private EventHandler<PortEventArgs> _event;
        private IPAddress _ip;

        public CheckPortTask(EventHandler<PortEventArgs> Event, IPAddress ip)
        {
            _event = Event;
            _ip = ip;
        }

        public void BeginCheckPort(UInt16 port)
        {
            BeginCheckPortTcp(port);
        }

        private delegate bool CheckPort(UInt16 port);

        //#region UDP
        //public IAsyncResult BeginCheckPortUdp(UInt16 portToCheck)
        //{
        //    AsyncUdpClient udpClient = new AsyncUdpClient();
        //    AsyncState asyncState = new AsyncState(portToCheck, udpClient);
        //    return udpClient.BeginConnect(_ip, portToCheck, new AsyncCallback(EndCheckPortUdp), asyncState);
        //}

        //public void EndCheckPortUdp(IAsyncResult ar)
        //{
        //    AsyncState asyncState = ar.AsyncState as AsyncState;
        //    AsyncUdpClient client = asyncState.Client as AsyncUdpClient;
        //    UInt16 port = asyncState.Port;
        //    Boolean connected = client.Connected;

        //    try
        //    {
        //        client.EndConnect(ar);

        //        if (_event != null)
        //            _event(this, new PortEventArgs(port, connected, (connected) ? "Succesfully connected!" : "Unable to connect!"));
        //    }
        //    catch (Exception e)
        //    {
        //        if (_event != null)
        //            _event(this, new PortEventArgs(port, false, e.Message));
        //    }
        //}
        //#endregion

        #region TCP

        public IAsyncResult BeginCheckPortTcp(UInt16 portToCheck)
        {
            TcpClient tcpClient = new TcpClient();
            tcpClient.Client.SendTimeout = 1000;
            tcpClient.Client.ReceiveTimeout = 1000;
            AsyncState asyncState = new AsyncState(portToCheck, tcpClient);

            try
            {
                return tcpClient.BeginConnect(_ip, portToCheck, new AsyncCallback(EndCheckPortTcp), asyncState);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);

                if (_event != null)
                    _event(this, new PortEventArgs(portToCheck, false, e.Message));
            }

            return null;
        }

        //if (connected)
        //{
        //    NetworkStream _cStream = null;
        //    try
        //    {
        //        _cStream = client.();

        //        Byte[] msg = Encoding.ASCII.GetBytes("org.matthiware.portchecker");
        //        _cStream.Write(msg, 0, msg.Length);
        //        _cStream.Flush();

        //        Byte[] rcvd = new Byte[client.ReceiveBufferSize];
        //        String rcvdMsg = Encoding.ASCII.GetString(rcvd);
        //        _cStream.Read(rcvd, 0, rcvd.Length);
        //    }
        //    catch (Exception ex)
        //    {
        //        readSucces = false;
        //    }
        //    finally
        //    {
        //        if (_cStream != null)
        //            _cStream.Close();
        //    }
        //}

        public void EndCheckPortTcp(IAsyncResult ar)
        {
            AsyncState asyncState = ar.AsyncState as AsyncState;
            TcpClient client = asyncState.Client as TcpClient;
            UInt16 port = asyncState.Port;
            bool connected = client.Connected;

            try
            {
                NetworkStream _cStream = null;
                if (connected)
                {
                    
                    _cStream = client.GetStream();

                    Byte[] msg = Encoding.ASCII.GetBytes("org.matthiware.portchecker");
                    _cStream.Write(msg, 0, msg.Length);
                    _cStream.Flush();
                }

                client.EndConnect(ar);

                if (connected)
                    if (_cStream != null)
                        _cStream.Dispose(); _cStream = null;

                if (_event != null)
                    _event(this, new PortEventArgs(port, connected, (connected) ? "Succesfully connected!" : "Unable to connect!"));
            }
            catch (SocketException se)
            {
                if (_event != null)
                    _event(this, new PortEventArgs(port, connected, se.Message));
            }
            catch (System.IO.IOException ioe)
            {
                if (_event != null)
                    _event(this, new PortEventArgs(port, connected, (connected) ? "Succesfully connected! But unable to write." : ioe.Message));
            }
            catch (Exception e)
            {
                if (_event != null)
                    _event(this, new PortEventArgs(port, connected, e.Message));
            }
        }
        #endregion


    }

    
}
